home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / manageme / tcpdump-.001 / tcpdump-~ / tcpdump-3.0.2-linux / tcpdump-3.0.2 / print-snmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-21  |  22.1 KB  |  1,033 lines

  1. /*
  2.  * Copyright (c) 1990, 1991, 1993, 1994
  3.  *    John Robert LoVerso.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by John Robert LoVerso.
  11.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  12.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  13.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  14.  *
  15.  * This implementation has been influenced by the CMU SNMP release,
  16.  * by Steve Waldbusser.  However, this shares no code with that system.
  17.  * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
  18.  * Earlier forms of this implementation were derived and/or inspired by an
  19.  * awk script originally written by C. Philip Wood of LANL (but later
  20.  * heavily modified by John Robert LoVerso).  The copyright notice for
  21.  * that work is preserved below, even though it may not rightly apply
  22.  * to this file.
  23.  *
  24.  * This started out as a very simple program, but the incremental decoding
  25.  * (into the BE structure) complicated things.
  26.  *
  27.  #            Los Alamos National Laboratory
  28.  #
  29.  #    Copyright, 1990.  The Regents of the University of California.
  30.  #    This software was produced under a U.S. Government contract
  31.  #    (W-7405-ENG-36) by Los Alamos National Laboratory, which is
  32.  #    operated by the    University of California for the U.S. Department
  33.  #    of Energy.  The U.S. Government is licensed to use, reproduce,
  34.  #    and distribute this software.  Permission is granted to the
  35.  #    public to copy and use this software without charge, provided
  36.  #    that this Notice and any statement of authorship are reproduced
  37.  #    on all copies.  Neither the Government nor the University makes
  38.  #    any warranty, express or implied, or assumes any liability or
  39.  #    responsibility for the use of this software.
  40.  #    @(#)snmp.awk.x    1.1 (LANL) 1/15/90
  41.  */
  42. #ifndef lint
  43. static char rcsid[] =
  44.     "@(#) $Id: print-snmp.c,v 3.10 91/01/17 01:18:13 loverso Exp Locker: loverso $ (jlv)";
  45. #endif
  46.  
  47. #include <sys/param.h>
  48. #include <sys/time.h>
  49. #include <sys/types.h>
  50.  
  51. #include <stdio.h>
  52. #include <ctype.h>
  53. #include <string.h>
  54.  
  55. #include "interface.h"
  56. #include "addrtoname.h"
  57.  
  58. /*
  59.  * Universal ASN.1 types
  60.  * (we only care about the tag values for those allowed in the Internet SMI)
  61.  */
  62. char *Universal[] = {
  63.     "U-0",
  64.     "Boolean",
  65.     "Integer",
  66. #define INTEGER 2
  67.     "Bitstring",
  68.     "String",
  69. #define STRING 4
  70.     "Null",
  71. #define ASN_NULL 5
  72.     "ObjID",
  73. #define OBJECTID 6
  74.     "ObjectDes",
  75.     "U-8","U-9","U-10","U-11",    /* 8-11 */
  76.     "U-12","U-13","U-14","U-15",    /* 12-15 */
  77.     "Sequence",
  78. #define SEQUENCE 16
  79.     "Set"
  80. };
  81.  
  82. /*
  83.  * Application-wide ASN.1 types from the Internet SMI and their tags
  84.  */
  85. char *Application[] = {
  86.     "IpAddress",
  87. #define IPADDR 0
  88.     "Counter",
  89. #define COUNTER 1
  90.     "Gauge",
  91. #define GAUGE 2
  92.     "TimeTicks",
  93. #define TIMETICKS 3
  94.     "Opaque"
  95. };
  96.  
  97. /*
  98.  * Context-specific ASN.1 types for the SNMP PDUs and their tags
  99.  */
  100. char *Context[] = {
  101.     "GetRequest",
  102. #define GETREQ 0
  103.     "GetNextRequest",
  104. #define GETNEXTREQ 1
  105.     "GetResponse",
  106. #define GETRESP 2
  107.     "SetRequest",
  108. #define SETREQ 3
  109.     "Trap"
  110. #define TRAP 4
  111. };
  112.  
  113. /*
  114.  * Private ASN.1 types
  115.  * The Internet SMI does not specify any
  116.  */
  117. char *Private[] = {
  118.     "P-0"
  119. };
  120.  
  121. /*
  122.  * error-status values for any SNMP PDU
  123.  */
  124. char *ErrorStatus[] = {
  125.     "noError",
  126.     "tooBig",
  127.     "noSuchName",
  128.     "badValue",
  129.     "readOnly",
  130.     "genErr"
  131. };
  132. #define DECODE_ErrorStatus(e) \
  133.     ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \
  134.     ? ErrorStatus[e] : (sprintf(errbuf, "err=%d", e), errbuf))
  135.  
  136. /*
  137.  * generic-trap values in the SNMP Trap-PDU
  138.  */
  139. char *GenericTrap[] = {
  140.     "coldStart",
  141.     "warmStart",
  142.     "linkDown",
  143.     "linkUp",
  144.     "authenticationFailure",
  145.     "egpNeighborLoss",
  146.     "enterpriseSpecific"
  147. #define GT_ENTERPRISE 7
  148. };
  149. #define DECODE_GenericTrap(t) \
  150.     ( t >= 0 && t <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) \
  151.     ? GenericTrap[t] : (sprintf(buf, "gt=%d", t), buf))
  152.  
  153. /*
  154.  * ASN.1 type class table
  155.  * Ties together the preceding Universal, Application, Context, and Private
  156.  * type definitions.
  157.  */
  158. #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
  159. struct {
  160.     char    *name;
  161.     char    **Id;
  162.     int    numIDs;
  163. } Class[] = {
  164.     defineCLASS(Universal),
  165. #define    UNIVERSAL    0
  166.     defineCLASS(Application),
  167. #define    APPLICATION    1
  168.     defineCLASS(Context),
  169. #define    CONTEXT        2
  170.     defineCLASS(Private),
  171. #define    PRIVATE        3
  172. };
  173.  
  174. /*
  175.  * defined forms for ASN.1 types
  176.  */
  177. char *Form[] = {
  178.     "Primitive",
  179. #define PRIMITIVE    0
  180.     "Constructed",
  181. #define CONSTRUCTED    1
  182. };
  183.  
  184. /*
  185.  * A structure for the OID tree for the compiled-in MIB.
  186.  * This is stored as a general-order tree.
  187.  */
  188. struct obj {
  189.     char    *desc;            /* name of object */
  190.     u_char    oid;            /* sub-id following parent */
  191.     u_char    type;            /* object type (unused) */
  192.     struct obj *child, *next;    /* child and next sibling pointers */
  193. } *objp = NULL;
  194.  
  195. /*
  196.  * Include the compiled in SNMP MIB.  "mib.h" is produced by feeding
  197.  * RFC-1156 format files into "makemib".  "mib.h" MUST define at least
  198.  * a value for `mibroot'.
  199.  *
  200.  * In particular, this is gross, as this is including initialized structures,
  201.  * and by right shouldn't be an "include" file.
  202.  */
  203. #include "mib.h"
  204.  
  205. /*
  206.  * This defines a list of OIDs which will be abbreviated on output.
  207.  * Currently, this includes the prefixes for the Internet MIB, the
  208.  * private enterprises tree, and the experimental tree.
  209.  */
  210. struct obj_abrev {
  211.     char *prefix;            /* prefix for this abrev */
  212.     struct obj *node;        /* pointer into object table */
  213.     char *oid;            /* ASN.1 encoded OID */
  214. } obj_abrev_list[] = {
  215. #ifndef NO_ABREV_MIB
  216.     /* .iso.org.dod.internet.mgmt.mib */
  217.     { "",    &_mib_obj,        "\53\6\1\2\1" },
  218. #endif
  219. #ifndef NO_ABREV_ENTER
  220.     /* .iso.org.dod.internet.private.enterprises */
  221.     { "E:",    &_enterprises_obj,    "\53\6\1\4\1" },
  222. #endif
  223. #ifndef NO_ABREV_EXPERI
  224.     /* .iso.org.dod.internet.experimental */
  225.     { "X:",    &_experimental_obj,    "\53\6\1\3" },
  226. #endif
  227.     { 0,0,0 }
  228. };
  229.  
  230. /*
  231.  * This is used in the OID print routine to walk down the object tree
  232.  * rooted at `mibroot'.
  233.  */
  234. #define OBJ_PRINT(o, suppressdot) \
  235. { \
  236.     if (objp) { \
  237.         do { \
  238.             if ((o) == objp->oid) \
  239.                 break; \
  240.         } while ((objp = objp->next) != NULL); \
  241.     } \
  242.     if (objp) { \
  243.         printf(suppressdot?"%s":".%s", objp->desc); \
  244.         objp = objp->child; \
  245.     } else \
  246.         printf(suppressdot?"%u":".%u", (o)); \
  247. }
  248.  
  249. /*
  250.  * This is the definition for the Any-Data-Type storage used purely for
  251.  * temporary internal representation while decoding an ASN.1 data stream.
  252.  */
  253. struct be {
  254.     u_long asnlen;
  255.     union {
  256.         caddr_t raw;
  257.         long integer;
  258.         u_long uns;
  259.         const u_char *str;
  260.     } data;
  261.     u_char form, class, id;        /* tag info */
  262.     u_char type;
  263. #define BE_ANY        255
  264. #define BE_NONE        0
  265. #define BE_NULL        1
  266. #define BE_OCTET    2
  267. #define BE_OID        3
  268. #define BE_INT        4
  269. #define BE_UNS        5
  270. #define BE_STR        6
  271. #define BE_SEQ        7
  272. #define BE_INETADDR    8
  273. #define BE_PDU        9
  274. };
  275.  
  276. /*
  277.  * Defaults for SNMP PDU components
  278.  */
  279. #define DEF_COMMUNITY "public"
  280. #define DEF_VERSION 0
  281.  
  282. /*
  283.  * constants for ASN.1 decoding
  284.  */
  285. #define OIDMUX 40
  286. #define ASNLEN_INETADDR 4
  287. #define ASN_SHIFT7 7
  288. #define ASN_SHIFT8 8
  289. #define ASN_BIT8 0x80
  290. #define ASN_LONGLEN 0x80
  291.  
  292. #define ASN_ID_BITS 0x1f
  293. #define ASN_FORM_BITS 0x20
  294. #define ASN_FORM_SHIFT 5
  295. #define ASN_CLASS_BITS 0xc0
  296. #define ASN_CLASS_SHIFT 6
  297.  
  298. #define ASN_ID_EXT 0x1f        /* extension ID in tag field */
  299.  
  300. /*
  301.  * truncated==1 means the packet was complete, but we don't have all of
  302.  * it to decode.
  303.  */
  304. static int truncated;
  305. #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
  306.  
  307. /*
  308.  * This decodes the next ASN.1 object in the stream pointed to by "p"
  309.  * (and of real-length "len") and stores the intermediate data in the
  310.  * provided BE object.
  311.  *
  312.  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
  313.  * O/w, this returns the number of bytes parsed from "p".
  314.  */
  315. static int
  316. asn1_parse(register const u_char *p, int len, struct be *elem)
  317. {
  318.     u_char form, class, id;
  319.     int i, hdr;
  320.  
  321.     elem->asnlen = 0;
  322.     elem->type = BE_ANY;
  323.     if (len < 1) {
  324.         ifNotTruncated puts("[nothing to parse], stdout");
  325.         return -1;
  326.     }
  327.  
  328.     /*
  329.      * it would be nice to use a bit field, but you can't depend on them.
  330.      *  +---+---+---+---+---+---+---+---+
  331.      *  + class |frm|        id         |
  332.      *  +---+---+---+---+---+---+---+---+
  333.      *    7   6   5   4   3   2   1   0
  334.      */
  335.     id = *p & ASN_ID_BITS;        /* lower 5 bits, range 00-1f */
  336. #ifdef notdef
  337.     form = (*p & 0xe0) >> 5;    /* move upper 3 bits to lower 3 */
  338.     class = form >> 1;        /* bits 7&6 -> bits 1&0, range 0-3 */
  339.     form &= 0x1;            /* bit 5 -> bit 0, range 0-1 */
  340. #else
  341.     form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
  342.     class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
  343. #endif
  344.     elem->form = form;
  345.     elem->class = class;
  346.     elem->id = id;
  347.     if (vflag)
  348.         printf("|%.2x", *p);
  349.     p++; len--; hdr = 1;
  350.     /* extended tag field */
  351.     if (id == ASN_ID_EXT) {
  352.         for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
  353.             if (vflag)
  354.                 printf("|%.2x", *p);
  355.             id += *p & ~ASN_BIT8;
  356.         }
  357.         if (len == 0 && *p & ASN_BIT8) {
  358.             ifNotTruncated fputs("[Xtagfield?]", stdout);
  359.             return -1;
  360.         }
  361.     }
  362.     if (len < 1) {
  363.         ifNotTruncated fputs("[no asnlen]", stdout);
  364.         return -1;
  365.     }
  366.     elem->asnlen = *p;
  367.     if (vflag)
  368.         printf("|%.2x", *p);
  369.     p++; len--; hdr++;
  370.     if (elem->asnlen & ASN_BIT8) {
  371.         int noct = elem->asnlen % ASN_BIT8;
  372.         elem->asnlen = 0;
  373.         if (len < noct) {
  374.             ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
  375.             return -1;
  376.         }
  377.         for (; noct-- > 0; len--, hdr++) {
  378.             if (vflag)
  379.                 printf("|%.2x", *p);
  380.             elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
  381.         }
  382.     }
  383.     if (len < elem->asnlen) {
  384.         if (!truncated) {
  385.             printf("[len%d<asnlen%u]", len, elem->asnlen);
  386.             return -1;
  387.         }
  388.         /* maybe should check at least 4? */
  389.         elem->asnlen = len;
  390.     }
  391.     if (form >= sizeof(Form)/sizeof(Form[0])) {
  392.         ifNotTruncated printf("[form?%d]", form);
  393.         return -1;
  394.     }
  395.     if (class >= sizeof(Class)/sizeof(Class[0])) {
  396.         ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
  397.         return -1;
  398.     }
  399.     if (id >= Class[class].numIDs) {
  400.         ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
  401.             Class[class].name, id);
  402.         return -1;
  403.     }
  404.  
  405.     switch (form) {
  406.     case PRIMITIVE:
  407.         switch (class) {
  408.         case UNIVERSAL:
  409.             switch (id) {
  410.             case STRING:
  411.                 elem->type = BE_STR;
  412.                 elem->data.str = p;
  413.                 break;
  414.  
  415.             case INTEGER: {
  416.                 register long data;
  417.                 elem->type = BE_INT;
  418.                 data = 0;
  419.  
  420.                 if (*p & ASN_BIT8)    /* negative */
  421.                     data = -1;
  422.                 for (i = elem->asnlen; i-- > 0; p++)
  423.                     data = (data << ASN_SHIFT8) | *p;
  424.                 elem->data.integer = data;
  425.                 break;
  426.             }
  427.  
  428.             case OBJECTID:
  429.                 elem->type = BE_OID;
  430.                 elem->data.raw = (caddr_t)p;
  431.                 break;
  432.  
  433.             case ASN_NULL:
  434.                 elem->type = BE_NULL;
  435.                 elem->data.raw = NULL;
  436.                 break;
  437.  
  438.             default:
  439.                 elem->type = BE_OCTET;
  440.                 elem->data.raw = (caddr_t)p;
  441.                 printf("[P/U/%s]",
  442.                     Class[class].Id[id]);
  443.                 break;
  444.             }
  445.             break;
  446.  
  447.         case APPLICATION:
  448.             switch (id) {
  449.             case IPADDR:
  450.                 elem->type = BE_INETADDR;
  451.                 elem->data.raw = (caddr_t)p;
  452.                 break;
  453.  
  454.             case COUNTER:
  455.             case GAUGE:
  456.             case TIMETICKS: {
  457.                 register u_long data;
  458.                 elem->type = BE_UNS;
  459.                 data = 0;
  460.                 for (i = elem->asnlen; i-- > 0; p++)
  461.                     data = (data << 8) + *p;
  462.                 elem->data.uns = data;
  463.                 break;
  464.             }
  465.  
  466.             default:
  467.                 elem->type = BE_OCTET;
  468.                 elem->data.raw = (caddr_t)p;
  469.                 printf("[P/A/%s]",
  470.                     Class[class].Id[id]);
  471.                 break;
  472.             }
  473.             break;
  474.  
  475.         default:
  476.             elem->type = BE_OCTET;
  477.             elem->data.raw = (caddr_t)p;
  478.             printf("[P/%s/%s]",
  479.                 Class[class].name, Class[class].Id[id]);
  480.             break;
  481.         }
  482.         break;
  483.  
  484.     case CONSTRUCTED:
  485.         switch (class) {
  486.         case UNIVERSAL:
  487.             switch (id) {
  488.             case SEQUENCE:
  489.                 elem->type = BE_SEQ;
  490.                 elem->data.raw = (caddr_t)p;
  491.                 break;
  492.  
  493.             default:
  494.                 elem->type = BE_OCTET;
  495.                 elem->data.raw = (caddr_t)p;
  496.                 printf("C/U/%s", Class[class].Id[id]);
  497.                 break;
  498.             }
  499.             break;
  500.  
  501.         case CONTEXT:
  502.             elem->type = BE_PDU;
  503.             elem->data.raw = (caddr_t)p;
  504.             break;
  505.  
  506.         default:
  507.             elem->type = BE_OCTET;
  508.             elem->data.raw = (caddr_t)p;
  509.             printf("C/%s/%s",
  510.                 Class[class].name, Class[class].Id[id]);
  511.             break;
  512.         }
  513.         break;
  514.     }
  515.     p += elem->asnlen;
  516.     len -= elem->asnlen;
  517.     return elem->asnlen + hdr;
  518. }
  519.  
  520. /*
  521.  * Display the ASN.1 object represented by the BE object.
  522.  * This used to be an integral part of asn1_parse() before the intermediate
  523.  * BE form was added.
  524.  */
  525. static void
  526. asn1_print(struct be *elem)
  527. {
  528.     u_char *p = (u_char *)elem->data.raw;
  529.     u_long asnlen = elem->asnlen;
  530.     int i;
  531.  
  532.     switch (elem->type) {
  533.  
  534.     case BE_OCTET:
  535.         for (i = asnlen; i-- > 0; p++);
  536.             printf("_%.2x", *p);
  537.         break;
  538.  
  539.     case BE_NULL:
  540.         break;
  541.  
  542.     case BE_OID: {
  543.     int o = 0, first = -1, i = asnlen;
  544.  
  545.         if (!nflag && asnlen > 2) {
  546.             struct obj_abrev *a = &obj_abrev_list[0];
  547.             for (; a->node; a++) {
  548.                 if (!bcmp(a->oid, (char *)p, strlen(a->oid))) {
  549.                     objp = a->node->child;
  550.                     i -= strlen(a->oid);
  551.                     p += strlen(a->oid);
  552.                     fputs(a->prefix, stdout);
  553.                     first = 1;
  554.                     break;
  555.                 }
  556.             }
  557.         }
  558.         for (; i-- > 0; p++) {
  559.             o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
  560.             if (*p & ASN_LONGLEN)
  561.                 continue;
  562.  
  563.             /*
  564.              * first subitem encodes two items with 1st*OIDMUX+2nd
  565.              */
  566.             if (first < 0) {
  567.                 if (!nflag)
  568.                     objp = mibroot;
  569.                 first = 0;
  570.                 OBJ_PRINT(o/OIDMUX, first);
  571.                 o %= OIDMUX;
  572.             }
  573.             OBJ_PRINT(o, first);
  574.             if (--first < 0)
  575.                 first = 0;
  576.             o = 0;
  577.         }
  578.         break;
  579.     }
  580.  
  581.     case BE_INT:
  582.         printf("%ld", elem->data.integer);
  583.         break;
  584.  
  585.     case BE_UNS:
  586.         printf("%ld", elem->data.uns);
  587.         break;
  588.  
  589.     case BE_STR: {
  590.         register int printable = 1, first = 1;
  591.         const u_char *p = elem->data.str;
  592.         for (i = asnlen; printable && i-- > 0; p++)
  593.             printable = isprint(*p) || isspace(*p);
  594.         p = elem->data.str;
  595.         if (printable)
  596.             (void)fn_print(p, p + asnlen);
  597.         else
  598.             for (i = asnlen; i-- > 0; p++) {
  599.                 printf(first ? "%.2x" : "_%.2x", *p);
  600.                 first = 0;
  601.             }
  602.         break;
  603.     }
  604.  
  605.     case BE_SEQ:
  606.         printf("Seq(%d)", elem->asnlen);
  607.         break;
  608.  
  609.     case BE_INETADDR: {
  610.         char sep;
  611.         if (asnlen != ASNLEN_INETADDR)
  612.             printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
  613.         sep='[';
  614.         for (i = asnlen; i-- > 0; p++) {
  615.             printf("%c%u", sep, *p);
  616.             sep='.';
  617.         }
  618.         putchar(']');
  619.         break;
  620.     }
  621.  
  622.     case BE_PDU:
  623.         printf("%s(%d)",
  624.             Class[CONTEXT].Id[elem->id], elem->asnlen);
  625.         break;
  626.  
  627.     case BE_ANY:
  628.         fputs("[BE_ANY!?]", stdout);
  629.         break;
  630.  
  631.     default:
  632.         fputs("[be!?]", stdout);
  633.         break;
  634.     }
  635. }
  636.  
  637. #ifdef notdef
  638. /*
  639.  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
  640.  * This will work for any ASN.1 stream, not just an SNMP PDU.
  641.  *
  642.  * By adding newlines and spaces at the correct places, this would print in
  643.  * Rose-Normal-Form.
  644.  *
  645.  * This is not currently used.
  646.  */
  647. static void
  648. asn1_decode(u_char *p, int length)
  649. {
  650.     struct be elem;
  651.     int i = 0;
  652.  
  653.     while (i >= 0 && length > 0) {
  654.         i = asn1_parse(p, length, &elem);
  655.         if (i >= 0) {
  656.             fputs(" ", stdout);
  657.             asn1_print(&elem);
  658.             if (elem.type == BE_SEQ || elem.type == BE_PDU) {
  659.                 fputs(" {", stdout);
  660.                 asn1_decode(elem.data.raw, elem.asnlen);
  661.                 fputs(" }", stdout);
  662.             }
  663.             length -= i;
  664.             p += i;
  665.         }
  666.     }
  667. }
  668. #endif
  669.  
  670. /*
  671.  * General SNMP header
  672.  *    SEQUENCE {
  673.  *        version INTEGER {version-1(0)},
  674.  *        community OCTET STRING,
  675.  *        data ANY    -- PDUs
  676.  *    }
  677.  * PDUs for all but Trap: (see rfc1157 from page 15 on)
  678.  *    SEQUENCE {
  679.  *        request-id INTEGER,
  680.  *        error-status INTEGER,
  681.  *        error-index INTEGER,
  682.  *        varbindlist SEQUENCE OF
  683.  *            SEQUENCE {
  684.  *                name ObjectName,
  685.  *                value ObjectValue
  686.  *            }
  687.  *    }
  688.  * PDU for Trap:
  689.  *    SEQUENCE {
  690.  *        enterprise OBJECT IDENTIFIER,
  691.  *        agent-addr NetworkAddress,
  692.  *        generic-trap INTEGER,
  693.  *        specific-trap INTEGER,
  694.  *        time-stamp TimeTicks,
  695.  *        varbindlist SEQUENCE OF
  696.  *            SEQUENCE {
  697.  *                name ObjectName,
  698.  *                value ObjectValue
  699.  *            }
  700.  *    }
  701.  */
  702.  
  703. /*
  704.  * Decode SNMP varBind
  705.  */
  706. static void
  707. varbind_print(u_char pduid, const u_char *np, int length, int error)
  708. {
  709.     struct be elem;
  710.     int count = 0, ind;
  711.  
  712.     /* Sequence of varBind */
  713.     if ((count = asn1_parse(np, length, &elem)) < 0)
  714.         return;
  715.     if (elem.type != BE_SEQ) {
  716.         fputs("[!SEQ of varbind]", stdout);
  717.         asn1_print(&elem);
  718.         return;
  719.     }
  720.     if (count < length)
  721.         printf("[%d extra after SEQ of varbind]", length - count);
  722.     /* descend */
  723.     length = elem.asnlen;
  724.     np = (u_char *)elem.data.raw;
  725.  
  726.     for (ind = 1; length > 0; ind++) {
  727.         const u_char *vbend;
  728.         int vblength;
  729.  
  730.         if (!error || ind == error)
  731.             fputs(" ", stdout);
  732.  
  733.         /* Sequence */
  734.         if ((count = asn1_parse(np, length, &elem)) < 0)
  735.             return;
  736.         if (elem.type != BE_SEQ) {
  737.             fputs("[!varbind]", stdout);
  738.             asn1_print(&elem);
  739.             return;
  740.         }
  741.         vbend = np + count;
  742.         vblength = length - count;
  743.         /* descend */
  744.         length = elem.asnlen;
  745.         np = (u_char *)elem.data.raw;
  746.  
  747.         /* objName (OID) */
  748.         if ((count = asn1_parse(np, length, &elem)) < 0)
  749.             return;
  750.         if (elem.type != BE_OID) {
  751.             fputs("[objName!=OID]", stdout);
  752.             asn1_print(&elem);
  753.             return;
  754.         }
  755.         if (!error || ind == error)
  756.             asn1_print(&elem);
  757.         length -= count;
  758.         np += count;
  759.  
  760.         if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
  761.                 fputs("=", stdout);
  762.  
  763.         /* objVal (ANY) */
  764.         if ((count = asn1_parse(np, length, &elem)) < 0)
  765.             return;
  766.         if (pduid == GETREQ || pduid == GETNEXTREQ) {
  767.             if (elem.type != BE_NULL) {
  768.                 fputs("[objVal!=NULL]", stdout);
  769.                 asn1_print(&elem);
  770.             }
  771.         } else
  772.             if (error && ind == error && elem.type != BE_NULL)
  773.                 fputs("[err objVal!=NULL]", stdout);
  774.             if (!error || ind == error)
  775.                 asn1_print(&elem);
  776.  
  777.         length = vblength;
  778.         np = vbend;
  779.     }
  780. }
  781.  
  782. /*
  783.  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
  784.  */
  785. static void
  786. snmppdu_print(u_char pduid, const u_char *np, int length)
  787. {
  788.     struct be elem;
  789.     int count = 0, error;
  790.  
  791.     /* reqId (Integer) */
  792.     if ((count = asn1_parse(np, length, &elem)) < 0)
  793.         return;
  794.     if (elem.type != BE_INT) {
  795.         fputs("[reqId!=INT]", stdout);
  796.         asn1_print(&elem);
  797.         return;
  798.     }
  799.     /* ignore the reqId */
  800.     length -= count;
  801.     np += count;
  802.  
  803.     /* errorStatus (Integer) */
  804.     if ((count = asn1_parse(np, length, &elem)) < 0)
  805.         return;
  806.     if (elem.type != BE_INT) {
  807.         fputs("[errorStatus!=INT]", stdout);
  808.         asn1_print(&elem);
  809.         return;
  810.     }
  811.     error = 0;
  812.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  813.         && elem.data.integer != 0) {
  814.         char errbuf[10];
  815.         printf("[errorStatus(%s)!=0]",
  816.             DECODE_ErrorStatus(elem.data.integer));
  817.     } else if (elem.data.integer != 0) {
  818.         char errbuf[10];
  819.         printf(" %s", DECODE_ErrorStatus(elem.data.integer));
  820.         error = elem.data.integer;
  821.     }
  822.     length -= count;
  823.     np += count;
  824.  
  825.     /* errorIndex (Integer) */
  826.     if ((count = asn1_parse(np, length, &elem)) < 0)
  827.         return;
  828.     if (elem.type != BE_INT) {
  829.         fputs("[errorIndex!=INT]", stdout);
  830.         asn1_print(&elem);
  831.         return;
  832.     }
  833.     if ((pduid == GETREQ || pduid == GETNEXTREQ)
  834.         && elem.data.integer != 0)
  835.         printf("[errorIndex(%d)!=0]", elem.data.integer);
  836.     else if (elem.data.integer != 0) {
  837.         if (!error)
  838.             printf("[errorIndex(%d) w/o errorStatus]",
  839.                 elem.data.integer);
  840.         else {
  841.             printf("@%d", elem.data.integer);
  842.             error = elem.data.integer;
  843.         }
  844.     } else if (error) {
  845.         fputs("[errorIndex==0]", stdout);
  846.         error = 0;
  847.     }
  848.     length -= count;
  849.     np += count;
  850.  
  851.     varbind_print(pduid, np, length, error);
  852.     return;
  853. }
  854.  
  855. /*
  856.  * Decode SNMP Trap PDU
  857.  */
  858. static void
  859. trap_print(const u_char *np, int length)
  860. {
  861.     struct be elem;
  862.     int count = 0, generic;
  863.  
  864.     putchar(' ');
  865.  
  866.     /* enterprise (oid) */
  867.     if ((count = asn1_parse(np, length, &elem)) < 0)
  868.         return;
  869.     if (elem.type != BE_OID) {
  870.         fputs("[enterprise!=OID]", stdout);
  871.         asn1_print(&elem);
  872.         return;
  873.     }
  874.     asn1_print(&elem);
  875.     length -= count;
  876.     np += count;
  877.  
  878.     putchar(' ');
  879.  
  880.     /* agent-addr (inetaddr) */
  881.     if ((count = asn1_parse(np, length, &elem)) < 0)
  882.         return;
  883.     if (elem.type != BE_INETADDR) {
  884.         fputs("[agent-addr!=INETADDR]", stdout);
  885.         asn1_print(&elem);
  886.         return;
  887.     }
  888.     asn1_print(&elem);
  889.     length -= count;
  890.     np += count;
  891.  
  892.     /* generic-trap (Integer) */
  893.     if ((count = asn1_parse(np, length, &elem)) < 0)
  894.         return;
  895.     if (elem.type != BE_INT) {
  896.         fputs("[generic-trap!=INT]", stdout);
  897.         asn1_print(&elem);
  898.         return;
  899.     }
  900.     generic = elem.data.integer;
  901.     {
  902.         char buf[10];
  903.         printf(" %s", DECODE_GenericTrap(generic));
  904.     }
  905.     length -= count;
  906.     np += count;
  907.  
  908.     /* specific-trap (Integer) */
  909.     if ((count = asn1_parse(np, length, &elem)) < 0)
  910.         return;
  911.     if (elem.type != BE_INT) {
  912.         fputs("[specific-trap!=INT]", stdout);
  913.         asn1_print(&elem);
  914.         return;
  915.     }
  916.     if (generic != GT_ENTERPRISE) {
  917.         if (elem.data.integer != 0)
  918.             printf("[specific-trap(%d)!=0]", elem.data.integer);
  919.     } else
  920.         printf(" s=%d", elem.data.integer);
  921.     length -= count;
  922.     np += count;
  923.  
  924.     putchar(' ');
  925.  
  926.     /* time-stamp (TimeTicks) */
  927.     if ((count = asn1_parse(np, length, &elem)) < 0)
  928.         return;
  929.     if (elem.type != BE_UNS) {            /* XXX */
  930.         fputs("[time-stamp!=TIMETICKS]", stdout);
  931.         asn1_print(&elem);
  932.         return;
  933.     }
  934.     asn1_print(&elem);
  935.     length -= count;
  936.     np += count;
  937.  
  938.     varbind_print (TRAP, np, length, 0);
  939.     return;
  940. }
  941.  
  942. /*
  943.  * Decode SNMP header and pass on to PDU printing routines
  944.  */
  945. void
  946. snmp_print(const u_char *np, int length)
  947. {
  948.     struct be elem, pdu;
  949.     int count = 0;
  950.  
  951.     truncated = 0;
  952.  
  953.     /* truncated packet? */
  954.     if (np + length > snapend) {
  955.         truncated = 1;
  956.         length = snapend - np;
  957.     }
  958.  
  959.     putchar(' ');
  960.  
  961.     /* initial Sequence */
  962.     if ((count = asn1_parse(np, length, &elem)) < 0)
  963.         return;
  964.     if (elem.type != BE_SEQ) {
  965.         fputs("[!init SEQ]", stdout);
  966.         asn1_print(&elem);
  967.         return;
  968.     }
  969.     if (count < length)
  970.         printf("[%d extra after iSEQ]", length - count);
  971.     /* descend */
  972.     length = elem.asnlen;
  973.     np = (u_char *)elem.data.raw;
  974.     /* Version (Integer) */
  975.     if ((count = asn1_parse(np, length, &elem)) < 0)
  976.         return;
  977.     if (elem.type != BE_INT) {
  978.         fputs("[version!=INT]", stdout);
  979.         asn1_print(&elem);
  980.         return;
  981.     }
  982.     /* only handle version==0 */
  983.     if (elem.data.integer != DEF_VERSION) {
  984.         printf("[version(%d)!=0]", elem.data.integer);
  985.         return;
  986.     }
  987.     length -= count;
  988.     np += count;
  989.  
  990.     /* Community (String) */
  991.     if ((count = asn1_parse(np, length, &elem)) < 0)
  992.         return;
  993.     if (elem.type != BE_STR) {
  994.         fputs("[comm!=STR]", stdout);
  995.         asn1_print(&elem);
  996.         return;
  997.     }
  998.     /* default community */
  999.     if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
  1000.         sizeof(DEF_COMMUNITY) - 1))
  1001.         /* ! "public" */
  1002.         printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
  1003.     length -= count;
  1004.     np += count;
  1005.  
  1006.     /* PDU (Context) */
  1007.     if ((count = asn1_parse(np, length, &pdu)) < 0)
  1008.         return;
  1009.     if (pdu.type != BE_PDU) {
  1010.         fputs("[no PDU]", stdout);
  1011.         return;
  1012.     }
  1013.     if (count < length)
  1014.         printf("[%d extra after PDU]", length - count);
  1015.     asn1_print(&pdu);
  1016.     /* descend into PDU */
  1017.     length = pdu.asnlen;
  1018.     np = (u_char *)pdu.data.raw;
  1019.  
  1020.     switch (pdu.id) {
  1021.     case TRAP:
  1022.         trap_print(np, length);
  1023.         break;
  1024.     case GETREQ:
  1025.     case GETNEXTREQ:
  1026.     case GETRESP:
  1027.     case SETREQ:
  1028.         snmppdu_print(pdu.id, np, length);
  1029.         break;
  1030.     }
  1031.     return;
  1032. }
  1033.